<?php
declare(strict_types=1);

namespace app\command;

use think\console\Command;
use think\console\Input;
use think\console\Output;
use think\console\input\Option;
use app\model\{ExpressServiceProvider, ExpressPriceCache, Area};
use app\service\Kuaidi100Service;
use think\facade\{Db, Log, Cache};

class CacheExpressPrice extends Command
{
    // 缓存有效期(天)
    const CACHE_EXPIRE_DAYS = 1;
    
    // 价格变化预警阈值(百分比)
    const PRICE_CHANGE_THRESHOLD = 10;

    protected function configure()
    {
        $this->setName('cache:express_price')
            ->setDescription('Cache express prices from Kuaidi100')
            ->addOption('provider', null, Option::VALUE_OPTIONAL, '指定快递服务商ID')
            ->addOption('province', null, Option::VALUE_OPTIONAL, '指定省份')
            ->addOption('force', null, Option::VALUE_NONE, '强制更新所有价格');
    }

    protected function execute(Input $input, Output $output)
    {
        try {
            $output->writeln('Start caching express prices...');
            
            // 获取命令行参数
            $providerId = $input->getOption('provider');
            $provinceName = $input->getOption('province');
            $forceUpdate = $input->getOption('force');
            
            // 获取快递服务商
            $query = ExpressServiceProvider::where('status', 1);
            if ($providerId) {
                $query->where('id', $providerId);
            }
            $providers = $query->select();
            
            // 获取省份
            $query = Area::where('parent_id', 0);
            if ($provinceName) {
                $query->where('area_name', $provinceName);
            }
            $provinces = $query->select();
            
            // 获取城市
            $cities = Area::where('parent_id', '>', 0)
                ->where('level', 2)
                ->select();
            
            $kuaidi100Service = new Kuaidi100Service();
            $updatedCount = 0;
            $errorCount = 0;
            
            // 遍历所有可能的组合
            foreach ($providers as $provider) {
                foreach ($provinces as $fromProvince) {
                    foreach ($cities as $fromCity) {
                        if ($fromCity->parent_id != $fromProvince->id) {
                            continue;
                        }
                        
                        foreach ($provinces as $toProvince) {
                            foreach ($cities as $toCity) {
                                if ($toCity->parent_id != $toProvince->id) {
                                    continue;
                                }
                                
                                // 检查缓存是否需要更新
                                $cacheKey = sprintf(
                                    'express_price:%d:%s:%s:%s:%s',
                                    $provider->id,
                                    $fromProvince->area_name,
                                    $fromCity->area_name,
                                    $toProvince->area_name,
                                    $toCity->area_name
                                );
                                
                                $existingCache = ExpressPriceCache::where([
                                    'express_service_provider_id' => $provider->id,
                                    'from_province' => $fromProvince->area_name,
                                    'from_city' => $fromCity->area_name,
                                    'to_province' => $toProvince->area_name,
                                    'to_city' => $toCity->area_name
                                ])->find();
                                
                                // 如果缓存未过期且不是强制更新,则跳过
                                if (!$forceUpdate && $existingCache && 
                                    strtotime($existingCache->update_time) > strtotime('-'.self::CACHE_EXPIRE_DAYS.' days')) {
                                    continue;
                                }
                                
                                try {
                                    // 查询首重价格
                                    $firstPriceInfo = $kuaidi100Service->queryPrice(
                                        $provider->service_code,
                                        $fromProvince->area_name,
                                        $fromCity->area_name,
                                        $toProvince->area_name,
                                        $toCity->area_name,
                                        $provider->first_weight
                                    );
                                    
                                    // 查询续重价格
                                    $totalPriceInfo = $kuaidi100Service->queryPrice(
                                        $provider->service_code,
                                        $fromProvince->area_name,
                                        $fromCity->area_name,
                                        $toProvince->area_name,
                                        $toCity->area_name,
                                        $provider->first_weight + $provider->continued_weight
                                    );
                                    
                                    $continuedPrice = $totalPriceInfo['total_price'] - $firstPriceInfo['total_price'];
                                    
                                    // 检查价格变化
                                    if ($existingCache) {
                                        $firstPriceChange = abs($firstPriceInfo['total_price'] - $existingCache->first_price) / $existingCache->first_price * 100;
                                        $continuedPriceChange = abs($continuedPrice - $existingCache->continued_price) / $existingCache->continued_price * 100;
                                        
                                        if ($firstPriceChange > self::PRICE_CHANGE_THRESHOLD || 
                                            $continuedPriceChange > self::PRICE_CHANGE_THRESHOLD) {
                                            Log::warning(sprintf(
                                                'Price change alert - %s: %s %s -> %s %s (First: %.2f->%.2f, Continued: %.2f->%.2f)',
                                                $provider->service_code,
                                                $fromProvince->area_name,
                                                $fromCity->area_name,
                                                $toProvince->area_name,
                                                $toCity->area_name,
                                                $existingCache->first_price,
                                                $firstPriceInfo['total_price'],
                                                $existingCache->continued_price,
                                                $continuedPrice
                                            ));
                                        }
                                    }
                                    
                                    // 更新缓存
                                    ExpressPriceCache::updateOrCreate([
                                        'express_service_provider_id' => $provider->id,
                                        'from_province' => $fromProvince->area_name,
                                        'from_city' => $fromCity->area_name,
                                        'to_province' => $toProvince->area_name,
                                        'to_city' => $toCity->area_name
                                    ], [
                                        'first_weight' => $provider->first_weight,
                                        'first_price' => $firstPriceInfo['total_price'],
                                        'continued_weight' => $provider->continued_weight,
                                        'continued_price' => $continuedPrice,
                                        'update_time' => date('Y-m-d H:i:s')
                                    ]);
                                    
                                    $updatedCount++;
                                    $output->writeln(sprintf(
                                        'Cached price for %s: %s %s -> %s %s (First: %.2f, Continued: %.2f)',
                                        $provider->service_code,
                                        $fromProvince->area_name,
                                        $fromCity->area_name,
                                        $toProvince->area_name,
                                        $toCity->area_name,
                                        $firstPriceInfo['total_price'],
                                        $continuedPrice
                                    ));
                                    
                                    usleep(200000);
                                    
                                } catch (\Exception $e) {
                                    $errorCount++;
                                    Log::error(sprintf(
                                        'Failed to cache price for %s: %s %s -> %s %s, error: %s',
                                        $provider->service_code,
                                        $fromProvince->area_name,
                                        $fromCity->area_name,
                                        $toProvince->area_name,
                                        $toCity->area_name,
                                        $e->getMessage()
                                    ));
                                    continue;
                                }
                            }
                        }
                    }
                }
            }
            
            $output->writeln(sprintf(
                'Express prices cached successfully! Updated: %d, Errors: %d',
                $updatedCount,
                $errorCount
            ));
            
        } catch (\Exception $e) {
            Log::error('Cache express prices failed: ' . $e->getMessage());
            $output->writeln('Cache express prices failed: ' . $e->getMessage());
        }
    }
} 